package cloud.example.eureka_client.service;

import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * @author zjm
 * @date 2018/12/22.
 */
@Component
public class RedisLockService {

  private static final Long EXPIRE_TIME = 10L;
  private static final String SET_IF_NOT_EXIST = "NX";
  private static final String SET_WITH_EXPIRE_TIME = "EX";

  private RedisTemplate<Object, Object> redisTemplate;

  public RedisLockService(RedisTemplate<Object, Object> redisTemplate) {
    this.redisTemplate = redisTemplate;
  }


  @SuppressWarnings("unchecked")
  public Boolean lock(String key, String value) {
    String lockKey = "lock:" + key;
    return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
      byte[] redisKeyBytes = keySerializer().serialize(lockKey);
      byte[] valueBytes = valueSerializer().serialize(value);
      Expiration expiration = Expiration.from(EXPIRE_TIME, TimeUnit.SECONDS);
      connection.set(redisKeyBytes, valueBytes, expiration, RedisStringCommands.SetOption.SET_IF_ABSENT);
      return redisTemplate.hasKey(lockKey);
    });
  }

  private RedisSerializer valueSerializer() {
    return redisTemplate.getValueSerializer();
  }

  private RedisSerializer keySerializer() {
    return redisTemplate.getKeySerializer();
  }

  public void unLock(String key) {
    String lockKey = "lock:" + key;
    redisTemplate.delete(lockKey);
  }

}
